package com.ruoyi.project.module.group.service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.framework.web.exception.AjaxResultException;
import com.ruoyi.project.module.application.domain.Application;
import com.ruoyi.project.module.applicationProperty.domain.ApplicationProperty;
import com.ruoyi.project.module.applicationProperty.service.IApplicationPropertyService;
import com.ruoyi.project.module.group.domain.ApplicationPropertyTree;
import com.ruoyi.project.module.group.domain.GroupPropertyTree;
import com.ruoyi.project.module.groupProperty.domain.GroupProperty;
import com.ruoyi.project.module.groupProperty.mapper.GroupPropertyMapper;
import com.ruoyi.project.module.groupProperty.service.IGroupPropertyService;
import com.ruoyi.project.module.task.mapper.TaskUtilsMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.project.module.group.mapper.GroupMapper;
import com.ruoyi.project.module.group.domain.Group;
import com.ruoyi.project.module.group.service.IGroupService;
import com.ruoyi.common.support.Convert;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * com.ruoyi.project.module.group.service.GroupServiceImpl
 * <br>
 *
 * @author shoukaiseki
 * ブログ http://www.shoukaiseki.top/<br>
 * E-メール jiang28555@Gmail.com<br>
 * @date 2019-04-16 17:25:51<br>
 */

@Service
public class GroupServiceImpl implements IGroupService 
{

	static final Logger logger= LoggerFactory.getLogger(GroupServiceImpl.class);

	@Resource
	TaskUtilsMapper taskUtilsMapper;

	@Resource
	private IGroupPropertyService groupPropertyService;

	@Resource
	GroupPropertyMapper groupPropertyMapper;

	@Resource
	private GroupMapper groupMapper;

	@Resource
	IApplicationPropertyService applicationPropertyService;

	/**
     * 查询配置组信息
     * 
     * @param configGroupId 配置组ID
     * @return 配置组信息
     */
    @Override
	public Group selectGroupById(Long configGroupId)
	{
	    return groupMapper.selectGroupById(configGroupId);
	}
	
	/**
     * 查询配置组列表
     * 
     * @param group 配置组信息
     * @return 配置组集合
     */
	@Override
	public List<Group> selectGroupList(Group group)
	{
	    return groupMapper.selectGroupList(group);
	}
	
    /**
     * 新增配置组
     * 
     * @param group 配置组信息
     * @return 结果
     */
	@Override
	public int insertGroup(Group group)
	{
		Date currentDate = taskUtilsMapper.getCurrentDate();
		String userName = ShiroUtils.getUser().getLoginName();
		group.setCreateBy(userName);
		group.setCreateTime(currentDate);
		group.setUpdateBy(userName);
		group.setUpdateTime(currentDate);
		group.setModify(1);
	    return groupMapper.insertGroup(group);
	}


	/**
     * 修改配置组
     * 
     * @param group 配置组信息
     * @return 结果
     */
	@Override
	public int updateGroup(Group group)
	{
		Date currentDate = taskUtilsMapper.getCurrentDate();
		String userName = ShiroUtils.getUser().getLoginName();
		group.setCreateBy(null);
		group.setCreateTime(null);
		group.setUpdateBy(userName);
		group.setUpdateTime(currentDate);
		group.setModify(1);
	    return groupMapper.updateGroup(group);
	}

	/**
     * 删除配置组对象
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
	@Override
	public int deleteGroupByIds(String ids)
	{
		return groupMapper.deleteGroupByIds(Convert.toStrArray(ids));
	}

	@Override
	public boolean hasChilds(Long uniqueId) {
		GroupProperty groupProperty = new GroupProperty();
		groupProperty.setConfigGroupId(uniqueId);
		int childSize=groupPropertyMapper.selectGroupPropertyList(groupProperty).size();
		return childSize==0?false:true;
	}

	/**
	 * 复制配置组
	 *
	 * @param group 配置组信息
	 * @return 结果
	 */
	@Override
	@Transactional
	public int copyGroup(Long sourceConfigGroupId, Group group)
	{
		String userName = ShiroUtils.getUser().getLoginName();
		group.setCreateBy(userName);
		group.setCreateTime(new Date());
		group.setUpdateBy(userName);
		group.setUpdateTime(new Date());
		group.setModify(1);
		int i = groupMapper.insertGroup(group);
		groupPropertyService.copy(sourceConfigGroupId,0L,group.getConfigGroupId(),0L);
		return i;
	}

	@Override
	@Transactional
	public void release(Long configGroupId, Long[] appIds) {

		for (Long appId : appIds) {
			release(configGroupId, appId);
		}
	}

	public void release(Long configGroupId, Long appId){
		Group configGroup = selectGroupById(configGroupId);
		GroupPropertyTree rootGP=new GroupPropertyTree();
		rootGP.setConfigGroupId(configGroupId);
		rootGP.setConfigGroupPropertyId(0L);

		List<GroupPropertyTree> groupPropertyTrees = groupPropertyTree(rootGP,rootGP,null);
		rootGP.addChildren(groupPropertyTrees);

		if(rootGP.getNodeList()==null||rootGP.getNodeList().isEmpty()){
			throw new AjaxResultException("配置组属性不能为空");
		}

		List<ApplicationPropertyTree> applicationPropertyTrees = applicationPropertiesTree(rootGP, configGroupId, appId);

		for (ApplicationPropertyTree applicationPropertyTree : applicationPropertyTrees) {
		    updateApplicationProperty(appId,configGroup,applicationPropertyTree,rootGP);
			logger.debug("--------{}",applicationPropertyTree.getConfigApplicationPropertyId());
		}
	}


	public void updateApplicationProperty(Long appId,Group configGroup,ApplicationPropertyTree applicationPropertyTree,GroupPropertyTree groupPropertyTree){
	    if(groupPropertyTree.getChildrenList()==null){
	    	return;
		}
		for (GroupPropertyTree groupPropertyTreeTemp : groupPropertyTree.getChildrenList()) {
			if (applicationPropertyTree.getChildrenList()==null) {
				applicationPropertyTree.setChildrenList(Lists.newArrayList());
			}

			List<ApplicationPropertyTree> apListTemp = applicationPropertyTree.getChildrenList().stream().filter(u -> Objects.equals(u.getConfigGroupPropertyId(), groupPropertyTreeTemp.getConfigGroupPropertyId())).collect(Collectors.toList());
			if (apListTemp.size()>1) {
				List<Long> collect = apListTemp.stream().map(ApplicationProperty::getConfigApplicationPropertyId).collect(Collectors.toList());
				throw new AjaxResultException(String.format("配置组属性[%s]对应重复配置应用子级%s",groupPropertyTreeTemp.getConfigGroupPropertyId(),JSONObject.toJSONString(collect)));
			}
			ApplicationPropertyTree apTreeTemp=null;
			if (apListTemp.size()==1) {
			    apTreeTemp=apListTemp.get(0);
			    if(groupPropertyTreeTemp.getPushUpdate()){
			    	if(apTreeTemp.getPushUpdate()){
						apTreeTemp.setPropKey(groupPropertyTreeTemp.getPropKey());
						apTreeTemp.setPropValue(groupPropertyTreeTemp.getPropValue());
						apTreeTemp.setConfigGroupId(groupPropertyTreeTemp.getConfigGroupId());
						apTreeTemp.setConfigGroupPropertyId(groupPropertyTreeTemp.getConfigGroupPropertyId());
						apTreeTemp.setDescription(groupPropertyTreeTemp.getDescription());
						apTreeTemp.setRemark(groupPropertyTreeTemp.getRemark());
						apTreeTemp.setGroupType(configGroup.getGroupType());
			    		applicationPropertyService.updateApplicationProperty(apTreeTemp);
					}
				}
            }else{
				//新增
				apTreeTemp=new ApplicationPropertyTree();
				apTreeTemp.setConfigApplicationId(appId);
				apTreeTemp.setPropKey(groupPropertyTreeTemp.getPropKey());
				apTreeTemp.setPropValue(groupPropertyTreeTemp.getPropValue());
				apTreeTemp.setConfigGroupId(groupPropertyTreeTemp.getConfigGroupId());
				apTreeTemp.setConfigGroupPropertyId(groupPropertyTreeTemp.getConfigGroupPropertyId());
				apTreeTemp.setParentId(applicationPropertyTree.getConfigApplicationPropertyId());
				apTreeTemp.setDescription(groupPropertyTreeTemp.getDescription());
				apTreeTemp.setGroupType(configGroup.getGroupType());
				apTreeTemp.setRemark(groupPropertyTreeTemp.getRemark());
				String propKey = groupPropertyTreeTemp.getPropKey();
				Objects.requireNonNull(propKey,"propKey不能为空."+JSONObject.toJSONString(groupPropertyTreeTemp));
				String fullNameOfProperty = new StringBuilder(applicationPropertyTree.getFullNameOfProperty())
						.append(".").append(propKey).toString();
				apTreeTemp.setFullNameOfProperty(fullNameOfProperty);
				int i = applicationPropertyService.insertApplicationProperty(apTreeTemp);
				if(i!=1){
					throw new RuntimeException("新增应用配置失败");
				}

			}

			if(apTreeTemp!=null){
				updateApplicationProperty(appId,configGroup,apTreeTemp,groupPropertyTreeTemp);
			}


		}


	}

	public List<ApplicationPropertyTree> applicationPropertiesTree(GroupPropertyTree rootGP,Long configGroupId,Long appId){
		ArrayList<ApplicationPropertyTree> list = Lists.newArrayList();
		Map<Long,ApplicationPropertyTree> apMap= Maps.newHashMap();
		ApplicationProperty applicationProperty = new ApplicationProperty();
		applicationProperty.setConfigGroupId(configGroupId);
		applicationProperty.setConfigApplicationId(appId);
		List<ApplicationProperty> applicationProperties = applicationPropertyService.selectApplicationPropertyList(applicationProperty);

		List<ApplicationProperty> apTemp = Lists.newArrayList(applicationProperties);

		for (ApplicationProperty property : applicationProperties) {
		    ApplicationPropertyTree propertyTree=apMap.get(property.getConfigApplicationPropertyId());
			if(propertyTree!=null){
			    continue;
            }

			propertyTree = new ApplicationPropertyTree();
			BeanUtils.copyProperties(property,propertyTree);
			apMap.put(propertyTree.getConfigApplicationPropertyId(),propertyTree);
			if (propertyTree.getParentId()==0) {
			    throw new AjaxResultException(String.format("配置组属性对应的配置应用属性parentId不可能为0.\n%s", JSONObject.toJSONString(property)));
			}


			GroupPropertyTree gpTree=initRelation(rootGP,null,propertyTree);

			if(gpTree.isRootNode()){
				if (!list.contains(propertyTree)) {
					list.add(propertyTree);
				}
			}else{
					ApplicationPropertyTree parentAP =propertyTree;
                    ApplicationPropertyTree childAP =propertyTree;
					GroupPropertyTree childGP=gpTree;
					do {

						parentAP=getParentAP(apMap,apTemp, parentAP);
						if (parentAP.getGpTree()!=null) {
							break;
						}
						GroupPropertyTree gpTemp = initRelation(rootGP,childGP, parentAP);
						if(gpTemp.isRootNode()){
						    parentAP.addChildrenList(childAP);
							if (!list.contains(parentAP)) {
								list.add(parentAP);
							}
							break;
						}
						childGP=gpTemp;
						childAP=parentAP;
					}while (true);
			}
		}

		return list;
	}

	/**
	 * 设置关联
	 * @param rootGP
	 * @param childGP		子级的GP,可以为空
	 * @param propertyTree
	 */
	public GroupPropertyTree initRelation(GroupPropertyTree rootGP,GroupPropertyTree childGP,ApplicationPropertyTree propertyTree){

		Optional<GroupPropertyTree> first = rootGP.getNodeList().stream().filter(u -> Objects.equals(u.getConfigGroupPropertyId(), propertyTree.getConfigGroupPropertyId())).findFirst();
		if(!first.isPresent()){
		    if(childGP.getParentTree().isRootNode()){
				GroupPropertyTree gpTree = rootGP;
				propertyTree.setGpTree(gpTree);
				gpTree.addApTree(propertyTree);
				return gpTree;
			}
			throw new AjaxResultException(String.format("配置应用属性对应的配置组属性不存在.\n%s", JSONObject.toJSONString(propertyTree)));
		}
		GroupPropertyTree gpTree = first.get();
		propertyTree.setGpTree(gpTree);
		gpTree.addApTree(propertyTree);
		return gpTree;
	}

	/**
	 * 获取 applicationProperty 的父级,如果 listAP 中不存在,则去数据库获取
	 * @param listAP
	 * @param propertyTreParam
	 * @return
	 */
	 public ApplicationPropertyTree getParentAP(Map<Long,ApplicationPropertyTree> apMap,List<ApplicationProperty> listAP,ApplicationPropertyTree propertyTreParam){
		 ApplicationPropertyTree parentTree = apMap.get(propertyTreParam.getParentId());
		 if(parentTree!=null){
		 	propertyTreParam.setParentTree(parentTree);
		 	parentTree.addChildrenList(propertyTreParam);
		     return parentTree;
		 }

		 Optional<ApplicationProperty> first = listAP.stream().filter(u -> Objects.equals(u.getConfigApplicationPropertyId(), propertyTreParam.getParentId())).findFirst();
		 if(first.isPresent()){

			 ApplicationProperty property = first.get();
			 ApplicationPropertyTree propertyTree = new ApplicationPropertyTree();
			 BeanUtils.copyProperties(property,propertyTree);
			 propertyTreParam.setParentTree(propertyTree);
			 apMap.put(propertyTree.getConfigApplicationPropertyId(),propertyTree);
			 propertyTree.addChildrenList(propertyTreParam);
			 return propertyTree;
		 }

		 ApplicationProperty applicationPropertyTemp = new ApplicationProperty();
		 applicationPropertyTemp.setConfigApplicationPropertyId(propertyTreParam.getParentId());
		 List<ApplicationProperty> applicationProperties = applicationPropertyService.selectApplicationPropertyList(applicationPropertyTemp);

		 if(applicationProperties==null||applicationProperties.size()==0){
			 throw new AjaxResultException(String.format("应用属性配置[%s]的父级无法从数据库获取",propertyTreParam.getParentId()));
		 }

		 ApplicationProperty property = applicationProperties.get(0);
		 ApplicationPropertyTree propertyTree = new ApplicationPropertyTree();
		 BeanUtils.copyProperties(property,propertyTree);
		 propertyTreParam.setParentTree(propertyTree);
		 apMap.put(propertyTree.getConfigApplicationPropertyId(),propertyTree);
		 propertyTree.addChildrenList(propertyTreParam);
		 return propertyTree;
	 }



	public List<GroupPropertyTree> groupPropertyTree(GroupPropertyTree rootGP,GroupPropertyTree parentGP,String fullNameOfProperty){
	    Long configGroupId=parentGP.getConfigGroupId();
	    Long parentId=parentGP.getConfigGroupPropertyId();
		List<GroupPropertyTree> list= Lists.newArrayList();
		List<GroupProperty> releaseGroupPropertyList = groupPropertyMapper.getReleaseGroupPropertyList(configGroupId,null,parentId);
		for (GroupProperty groupProperty : releaseGroupPropertyList) {
		    GroupPropertyTree groupPropertyTree=new GroupPropertyTree();
			BeanUtils.copyProperties(groupProperty,groupPropertyTree);
			list.add(groupPropertyTree);
			String fullNameOfPropertyTemp;
			if(fullNameOfProperty==null){
				fullNameOfPropertyTemp=groupProperty.getPropKey();
			}else{
				fullNameOfPropertyTemp=fullNameOfProperty+"."+groupProperty.getPropKey();
			}
			groupPropertyTree.setFullNameOfProperty(fullNameOfPropertyTemp);
			groupPropertyTree.setParentTree(parentGP);
			rootGP.addNode(groupPropertyTree);
			List<GroupPropertyTree> childrenList = groupPropertyTree(rootGP,groupPropertyTree,fullNameOfPropertyTemp);
			groupPropertyTree.addChildren(childrenList);
		}

		return list;
	}
}
